﻿using System;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Collections;

using Noris.Schedule.Support.Services;
using Noris.Schedule.Support.Core;

namespace Noris.Schedule.Support
{
	/// <summary>
	/// Hlavní správce podkladových dat aplikace.
	/// Používá se pro získání dat trvalého charakteru i pro volání systémových metod.
	/// </summary>
	/// <remarks>
	/// Obsahuje privátní singleton na svoji instanci, v níž uchovává trvalá data.
	/// Uchovává v sobě konfiguraci, reflexi výkonných tříd.
	/// </remarks>
	public partial class Steward
	{
		#region PŘÍSTUP DO INSTANCE TŘÍDY DiagnosticCls
		/// <summary>
		/// Odkaz na diagnostická data
		/// </summary>
		public static DiagnosticCls Diagnostic { get { return Current._Diagnostic; } }
		/// <summary>
		/// Instanční přístup k diagnostickým datům
		/// </summary>
		private DiagnosticCls _Diagnostic
		{
			get
			{
				if (this.__Diagnostic == null)
				{
					lock (__DiagnosticLock)
					{
                        if (this.__Diagnostic == null)
                        {
                            this.__Diagnostic = new DiagnosticCls();
                            this.__Diagnostic.DiagnosticEnabled = Steward.DebugMode;
                        }
					}
				}
				return this.__Diagnostic;
			}
		}
		/// <summary>
		/// Úložiště objektu, který představuje diagnostická data
		/// </summary>
		private DiagnosticCls __Diagnostic;
		/// <summary>
		/// Locker pro tvorbu objektu, který obsahuje diagnostická data
		/// </summary>
		private object __DiagnosticLock = new object();
		#endregion
	}
	#region CLASS DiagnosticCls : DIAGNOSTICKÁ DATA APLIKACE
	/// <summary>
	/// Diagnostická data aplikace
	/// </summary>
	public class DiagnosticCls
	{
		#region Konstrukce
		internal DiagnosticCls()
		{
			this._InfoSb = new StringBuilder();
            this.DiagnosticEnabled = false;
		}
		private StringBuilder _InfoSb;
        /// <summary>
        /// Příznak, že diagnostika je aktivní.
        /// Implicitní stav = false.
        /// Ve stavu false se neukládají diagnostické texty do interní paměti, nezapisuje se soubor ani se neprovede jeho otevření.
        /// Nastavením na true se toto vše povolí, ale dřívější diagnostické zápisy neexistují.
        /// Nastavením na false se dřívější zápisy neztratí. Jen se vypne příjem dalších.
        /// </summary>
        public bool DiagnosticEnabled { get; set; }
		#endregion
		#region Info text
		/// <summary>
		/// Vyčistí informace v property Info
		/// </summary>
		public void InfoClear()
		{
			this._InfoSb = new StringBuilder();
		}
        /// <summary>
        /// Vyčistí informace v property Info
        /// </summary>
        public void InfoClear(bool withFile)
        {
            this._InfoSb = new StringBuilder();
            if (withFile)
            {
                string fileName = this.FullName;
                if (File.Exists(fileName))
                    File.Delete(fileName);
            }
        }
        /// <summary>
        /// Do diagnostiky přidá podtitulek.
        /// Nemaže současný obsah.
        /// Titulek: před ním bude oddělovací dvojlinka (70 x rovnítko)
        /// Pod ní bude titulek zarovnaný vlevo.
        /// Pokud je na vstupu String.IsNullOrEmpty(), nebude se vkládat nic.
        /// </summary>
        /// <param name="title"></param>
        /// <param name="parameters">Paramety vkládané do textu na místo %0, %1, atd</param>
        public void SubTitleAdd(string title, params object[] parameters)
        {
            if (!this.DiagnosticEnabled) return;
            if (!String.IsNullOrEmpty(title))
            {
                this.InfoAddSeparatorLine('-');
                this.InfoAddLine(MessageInfo.ApplyParams(title, parameters));
            }
        }
        /// <summary>
        /// Do diagnostiky přidá titulek.
        /// Nemaže současný obsah.
        /// Titulek: před ním bude oddělovací dvojlinka (70 x rovnítko)
        /// Pod ní bude řádek obsahující datum a čas.
        /// Pak bude vycentrovaný titulek.
        /// Pak bude oddělovací linka (70 x pomlčka).
        /// </summary>
        /// <param name="title"></param>
        /// <param name="parameters">Paramety vkládané do textu na místo %0, %1, atd</param>
        public void TitleAdd(string title, params object[] parameters)
        {
            if (!this.DiagnosticEnabled) return;
            if (!String.IsNullOrEmpty(title))
            {
                this.InfoAddSeparatorLine('=');
                this.InfoAddLine("Time: " + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"));
                string text = MessageInfo.ApplyParams(title, parameters);
                int padL = 35 - (text.Length / 2);
                int padR = 70 - padL - text.Length;
                this.InfoAddLine(text.PadRight(padL).PadLeft(padR));
                this.InfoAddSeparatorLine('-');
            }
        }
		/// <summary>
		/// Do property Info přidá další text. Nepřidává konec řádku.
		/// </summary>
		/// <param name="infoText"></param>
        /// <param name="parameters">Paramety vkládané do textu na místo %0, %1, atd</param>
        public void InfoAdd(string infoText, params object[] parameters)
		{
            if (!this.DiagnosticEnabled) return;
            if (!String.IsNullOrEmpty(infoText))
                this._InfoSb.Append(MessageInfo.ApplyParams(infoText, parameters));
		}
        /// <summary>
        /// Do property Info přidá další text. Přidává konec řádku.
        /// </summary>
        /// <param name="infoText"></param>
        /// <param name="parameters">Paramety vkládané do textu na místo %0, %1, atd</param>
        public void InfoAddLine(string infoText, params object[] parameters)
        {
            if (!this.DiagnosticEnabled) return;
            if (!String.IsNullOrEmpty(infoText))
                this._InfoSb.AppendLine(MessageInfo.ApplyParams(infoText, parameters));
        }
        /// <summary>
        /// Do property Info přidá další text. Přidává konec řádku.
        /// Před text předsadí aktuální přesný čas.
        /// </summary>
        /// <param name="infoText"></param>
        /// <param name="parameters">Paramety vkládané do textu na místo %0, %1, atd</param>
        public void InfoAddLineWithTime(string infoText, params object[] parameters)
        {
            if (!this.DiagnosticEnabled) return;
            if (!String.IsNullOrEmpty(infoText))
                this._InfoSb.AppendLine(DateTime.Now.ToString("HH:mm:ss.fff") + "; " + MessageInfo.ApplyParams(infoText, parameters));
        }
        /// <summary>
		/// Do property Info přidá vodorovnou čáru jakožto separátor + přidá konec řádku.
		/// </summary>
		public void InfoAddSeparatorLine()
		{
            if (!this.DiagnosticEnabled) return;
            InfoAddSeparatorLine('=');
		}
		/// <summary>
		/// Do property Info přidá vodorovnou čáru jakožto separátor + přidá konec řádku.
		/// </summary>
		public void InfoAddSeparatorLine(char separator)
		{
            if (!this.DiagnosticEnabled) return;
            InfoAddLine("".PadLeft(70, separator));
		}
		/// <summary>
		/// Uloží diagnostickou informaci do Clipboardu
		/// </summary>
		public void InfoToClipboard()
		{
            if (!this.DiagnosticEnabled) return;
            if (this.InfoExists && System.Threading.Thread.CurrentThread.GetApartmentState() == System.Threading.ApartmentState.STA)
				System.Windows.Forms.Clipboard.SetText(this.Info);
		}
		/// <summary>
		/// Příznak, zda existuje diagnostický text (není null, je delší než 0)
		/// </summary>
		public bool InfoExists { get { return this._InfoSb != null && this._InfoSb.Length > 0; } }
		/// <summary>
		/// Aktuální obsah textu. Pokud neexistuje, vrací String.Empty
		/// </summary>
		public string Info { get { return (this.InfoExists ? this._InfoSb.ToString() : String.Empty); } }
		#endregion
        #region Save data
        /// <summary>
        /// Uloží diagnostická data.
        /// Ukládá je do souboru "Diagnostic.txt" v adresáři aplikace.
        /// Volitelně (parametrem) je možno specifikovat chování vzhledem k velikosti souboru (přepsat / odložit do dalšího).
        /// </summary>
        public void Save()
        {
            if (!this.DiagnosticEnabled) return;
            if (!this.InfoExists) return;

            string fileName = this.FullName;
            try
            {
                using (System.IO.StreamWriter sw = new StreamWriter(fileName, true, Encoding.UTF8))
                {
                    sw.Write(this.Info);
                    sw.Close();
                }
            }
            catch (System.UnauthorizedAccessException ex)
            {
                Dialog.ShowError(ex, MessageInfo.Get("Zápis do složky s programem (%0) není povolen.", Steward.ExecutablePath));
            }
            catch (System.Security.SecurityException ex)
            {
                Dialog.ShowError(ex, MessageInfo.Get("Pro zápis do složky s programem (%0) nemáte oprávnění.", Steward.ExecutablePath));
            }
            return;
        }
        /// <summary>
        /// Otevře soubor diagnostiky
        /// </summary>
        public void Open()
        {
            if (!this.DiagnosticEnabled) return;
            string fileName = this.FullName;
            if (File.Exists(fileName))
                System.Diagnostics.Process.Start(fileName);
        }
        /// <summary>
        /// Plné jméno souboru s diagnostikou
        /// </summary>
        public string FullName
        {
            get { return Path.Combine(Steward.ExecutablePath, "Diagnostic.txt"); }
        }
        #endregion
	}
	#endregion
}
